package org.finesys.common.redisson.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.finesys.common.redisson.annotation.DistributedLock;
import org.finesys.common.redisson.entity.LockEntity;
import org.finesys.common.redisson.factory.RedissonLockServiceFactory;
import org.finesys.common.redisson.lockResover.DistributedLockResolver;
import org.finesys.common.redisson.service.RedissonService;
import org.springframework.core.Ordered;

import cn.hutool.core.lang.Assert;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Aspect
public class DistributedLockAspect implements Ordered {

    @Around(value = "@@annotation(distributedLock)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint, DistributedLock distributedLock) throws Throwable {
        //获取锁的解析器
        DistributedLockResolver keyResolver = SpringUtil.getBean(distributedLock.lockResover());
        Assert.notNull(keyResolver, "找不到对应的DistributedLockResolver");
        //解析锁信息
        LockEntity lockEntity = keyResolver.resolver(proceedingJoinPoint, distributedLock);
        // 根据锁类型 获取redissonService
        RedissonService redissonService = RedissonLockServiceFactory.getLock(distributedLock.lockType());
        // 如果当前线程持有当前锁，则重入
        if (redissonService.getThreadLock() != null && !lockEntity.equals(redissonService.getThreadLock())) {
            return proceedingJoinPoint.proceed();
        }
        // 保存线程锁信息
        redissonService.saveThreadLock(lockEntity);
        boolean success = false;
        try {
            //枷锁
            success = redissonService.lock(lockEntity);
            if (!success) {
                String message = String.format("[%s]加锁失败,锁类型[%s]!", lockEntity.getLockName(), distributedLock.lockType());
                throw new RuntimeException(message);
            } else {
                return proceedingJoinPoint.proceed();
            }
        } finally {
            if (success) {
                //释放锁
                redissonService.unlock(lockEntity);
                //清空线程锁信息
                redissonService.clearThreadLock();
            }
        }
    }


    @Override
    public int getOrder() {
        return 0;
    }
}
